#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <functional>
#include <time.h>
#include "Session.hpp"
#include "Log.hpp"
const static std::string base_sep = "\r\n";
const static std::string space_sep = " ";
const static std::string line_sep = ": ";
const static std::string prefixpath = "wwwroot"; // web根目录
const static std::string homepage = "index.html";
const static std::string suffixsep = ".";
const static std::string httpversion = "HTTP/1.0";
const static std::string arg_sep = "?";
class HttpRequest
{
private:
    // 得到一行
    std::string GetLine(std::string &reqstr)
    {
        auto pos = reqstr.find(base_sep);
        if (pos == std::string::npos)
            return std::string();
        std::string line = reqstr.substr(0, pos);
        reqstr.erase(0, line.size() + base_sep.size());
        return line.empty() ? base_sep : line; // 如果读取到空白行那截取的就是空串，则直接返回空白行就可以
    }
    // 解析请求行
    void ParseReqline()
    {
        std::stringstream ss(_req_line);
        ss >> _method >> _url >> _version;

        std::string prefix = "Cookie: "; // cookie：sessionid=1233445
        for (auto &header : _req_headers)
        {
            std::string cookie;
            if (strncmp(header.c_str(), prefix.c_str(), sizeof(prefix)) == 0)
            {
                cookie = header.substr(prefix.size());
                _cookies.emplace_back(cookie);
                break; // 测试假设只有一条session
            }
        }

        prefix = "sessionid=";
        for (auto &cookie : _cookies)
        {
            if (strncmp(cookie.c_str(), prefix.c_str(), prefix.size()) == 0)
            {
                _sessionid = cookie.substr(prefix.size());
                break;
            }
        }
        _path += _url;
        // 添加一个首页
        if (_path[_path.size() - 1] == '/')
        {
            _path += homepage;
        }

        auto pos = _url.rfind(suffixsep);
        if (pos != std::string::npos)
        {
            _suffix = _path.substr(pos);
        }
        else
        {
            _suffix = ".default";
        }
    }

    void ParseReqHeader()
    {
        for (auto &header : _req_headers)
        {
            auto pos = header.find(line_sep);
            if (pos == std::string::npos)
                continue;
            std::string k = header.substr(0, pos);
            std::string v = header.substr(pos + line_sep.size());
            if (k.empty() || v.empty())
                continue;
            _headers_kv.insert(std::make_pair(k, v));
        }
    }

public:
    HttpRequest()
        : _blank_line(base_sep), _path(prefixpath)
    {
    }
    ~HttpRequest()
    {
    }
    void DeSerialize(std::string &reqstr)
    {
        // 粗力度反序列
        _req_line = GetLine(reqstr); // 请求行
        std::string header;          // 请求报头
        do
        {
            header = GetLine(reqstr);
            if (header.empty() || header == base_sep)
                break;
            _req_headers.push_back(header);
        } while (true);

        if (!reqstr.empty()) // 请求正文
        {
            _body_text = reqstr;
        }
        ParseReqline();
        ParseReqHeader();
    }

    void Print()
    {
        std::cout << "----------------------------" << std::endl;
        std::cout << "###" << _req_line << std::endl;
        for (auto &header : _req_headers)
        {
            std::cout << "@@@" << header << std::endl;
        }
        std::cout << "***" << _blank_line;
        std::cout << ">>>" << _body_text << std::endl;

        std::cout << "Method: " << _method << std::endl;
        std::cout << "Url: " << _url << std::endl;
        std::cout << "Version: " << _version << std::endl;

        for (auto &header_kv : _headers_kv)
        {
            std::cout << ")))" << header_kv.first << "->" << header_kv.second << std::endl;
        }
    }

    std::string Url()
    {
        LOG(DEBUG, "Client Want url %s\n", _url.c_str());
        return _url;
    }

    std::string Path()
    {
        LOG(DEBUG, "Client Want path %s\n", _path.c_str());
        return _path;
    }

    std::string Suffix()
    {
        return _suffix;
    }

    std::string Method()
    {
        LOG(DEBUG, "Client request method is %s\n", _method.c_str());
        return _method;
    }

    std::string GetResuestBody()
    {
        LOG(DEBUG, "Client request method is %s, args: %s, request path: %s\n",
            _method.c_str(), _body_text.c_str(), _path.c_str());
        return _body_text;
    }
    std::string Sessionid()
    {
        return _sessionid;
    }

private:
    // 基本HttpRequwst格式
    std::string _req_line;
    std::vector<std::string> _req_headers;
    std::string _blank_line;
    std::string _body_text;
    // 更详细的数据
    std::string _method;
    std::string _url;
    std::string _version;
    std::string _path;
    std::string _suffix; // 资源后缀
    std::unordered_map<std::string, std::string> _headers_kv;
    std::string _sessionid;
    std::vector<std::string> _cookies;
};

class HttpResponse
{
public:
    HttpResponse() : _verison(httpversion), _blank_line(base_sep)
    {
    }

    void AddCode(int code, const std::string &desc)
    {
        _status_code = code;
        _desc = desc;
    }

    void AddHeader(const std::string &k, const std::string &v)
    {
        _headers_kv[k] = v;
    }

    void AddBodyText(const std::string &body_text)
    {
        _resp_body_text = body_text;
    }

    std::string Serialize()
    {
        // 构建状态行
        _status_line = _verison + space_sep + std::to_string(_status_code) + space_sep + _desc + base_sep;
        // 2. 构建应答报头
        for (auto &header : _headers_kv)
        {
            std::string header_line = header.first + line_sep + header.second + base_sep;
            _resp_headers.push_back(header_line);
        }
        // 空行在构造函数实现了

        // 正式序列化
        std::string responsestr = _status_line;
        for (auto &line : _resp_headers)
        {
            responsestr += line;
        }
        responsestr += _blank_line;
        responsestr += _resp_body_text;

        return responsestr;
    }

private:
    // httpresponse base 属性
    std::string _verison;
    int _status_code;
    std::string _desc;
    std::unordered_map<std::string, std::string> _headers_kv;

    // 基本的httpResponse的格式
    std::string _status_line;
    std::vector<std::string> _resp_headers;
    std::string _blank_line;
    std::string _resp_body_text;
};

using func_t = std::function<HttpResponse(HttpRequest &)>;
class HttpServer
{
private:
    std::string GetFile(std::string path)
    {
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return std::string();

        in.seekg(0, in.end);
        int filesize = in.tellg(); // 计算rw偏移量
        in.seekg(0, in.beg);

        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();
        return content;
    }

public:
    HttpServer()
    {
        _mine_type.insert(std::make_pair(".html", "text/html"));
        _mine_type.insert(std::make_pair(".jpg", "image/jpeg"));
        _mine_type.insert(std::make_pair(".png", "image/png"));
        _mine_type.insert(std::make_pair(".default", "text/html"));

        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(201, "Created"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(std::make_pair(302, "Found"));
        _code_to_desc.insert(std::make_pair(404, "Not Found"));


        _session_manager = std::make_unique<SessionManager>();
    }

    std::string GetWeekDayName(int day)
    {
        std::vector<std::string> Week = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
        return Week[day];
    }

    std::string GetMonthName(int month)
    {
        std::vector<std::string> Months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
        return Months[month];
    }

    std::string ExpireTimeUseRfc1123(int t)
    {
        time_t timeout = time(nullptr) + t; // 获取未来t秒的时间戳
        struct tm *tm = gmtime(&timeout);
        char timebuffer[1024];
        // 时间格式如: expires=Thu, 18 Dec 2024 12:00:00 UTC
        snprintf(timebuffer, sizeof(timebuffer), "%s, %02d %s %d %02d:%02d:%02d UTC",
                 GetWeekDayName(tm->tm_wday).c_str(),
                 tm->tm_mday,
                 GetMonthName(tm->tm_mon).c_str(),
                 tm->tm_year + 1900,
                 tm->tm_hour,
                 tm->tm_min,
                 tm->tm_sec);
        return timebuffer;
    }

    std::string HandlerHttpRequest(std::string &reqstr)
    {
        std::cout << "---------------------------------------" << std::endl;
        std::cout << reqstr;
        std::cout << "---------------------------------------" << std::endl;

        HttpRequest req;
        req.DeSerialize(reqstr);

        HttpResponse resp;
        static int number = 0;
        if (req.Url() == "/login") // 模拟登录
        {
            std::string sessionid = req.Sessionid();
            if (sessionid.empty()) // 说明客户端第一次访问服务器,那就给客户端形成一个sessionid发送给他
            {
                std::string user = "user-" + std::to_string(number++);
                session_ptr s = std::make_shared<Session>(user, "123456");
                sessionid = _session_manager->AddSession(s);
                LOG(DEBUG, "%s 被添加, sessionid是: %s\n", user.c_str(), sessionid.c_str());
                resp.AddHeader("Set-Cookie", "sessionid=" + sessionid);
            }
        }
        else
        {
            std::string sessionid = req.Sessionid();
            if (!sessionid.empty())
            {
                session_ptr s = _session_manager->GetSession(sessionid);
                // 这个地方有坑，一定要判断服务器端session对象是否存在，因为可能测试的时候
                // 浏览器还有历史sessionid，但是服务器重启之后，session对象没有了.
                if (s != nullptr)
                {
                    LOG(DEBUG, "%s 正在活跃.\n", s->Username().c_str());
                }
                else
                {
                    LOG(DEBUG, "cookie : %s 已经过期, 需要清理\n", sessionid.c_str());
                }
            }
        }
        // 测试Cookie自动写入
        // resp.AddHeader("Set-Cookie","username=zhangsan;");
        // 测试写入Cookie过期时间
        // resp.AddHeader("Set-Cookie", "username=zhangsan; expires="+ExpireTimeUseRfc1123(30)+";");  //设置Cookie在30秒后过期
        // 测试路径path
        // resp.AddHeader("Set-Cookie", "username=zhangsan; path=/a/b");

        resp.AddCode(200, _code_to_desc[200]);
        resp.AddBodyText("<html><h1>helloworld</h1></html>");
        std::string respstr = resp.Serialize();
        return respstr;
    }

private:
    std::unordered_map<std::string, std::string> _mine_type;
    std::unordered_map<int, std::string> _code_to_desc;
    std::unordered_map<std::string, func_t> _service_list;
    std::unique_ptr<SessionManager> _session_manager;
};